/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.mvc.plugin;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

import com.zhg2yqq.wheels.mvc.annotation.XssEscape;
import com.zhg2yqq.wheels.mvc.annotation.XssField;

/**
 *
 * @version zhg2yqq v1.0
 * @author zhg2yqq, 2022年12月4日
 */
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.http.HtmlUtil;

@Aspect
public class XssEscapeArgumentAspect {
//    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
//    public void requestMappingPoint() {
//    }

    @Before("@annotation(org.springframework.web.bind.annotation.RequestMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.GetMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.PostMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.PutMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.PatchMapping)"
            + "|| @annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void escape(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (args.length == 0) {
            return;
        }

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            if (param.isAnnotationPresent(XssEscape.class)) {
                Object arg = args[i];
                args[i] = escape(arg);
            }
        }
    }

    public Object escape(Object o) {
        if (o == null) {
            return o;
        }
        Field[] fields = ReflectUtil.getFields(o.getClass(),
                f -> f.isAnnotationPresent(XssField.class) && String.class.equals(f.getType()));
        Arrays.stream(fields).forEach(f -> {
            String v = (String) ReflectUtil.getFieldValue(o, f);
            if (v != null) {
                ReflectUtil.setFieldValue(o, f, HtmlUtil.escape(v));
            }
        });
        return o;
    }
}
